package com.hiv.service;

import cn.hutool.core.codec.Base64;
import com.google.common.collect.Lists;
import com.hiv.common.PageInfo;
import com.hiv.common.enums.ErrorCode;
import com.hiv.common.param.AdminAccountAddParam;
import com.hiv.common.param.AdminAccountEditParam;
import com.hiv.common.param.RoleAddParam;
import com.hiv.common.param.RoleUpdateParam;
import com.hiv.common.param.page.PageQueryAdminParam;
import com.hiv.common.param.page.PageQueryRoleParam;
import com.hiv.common.response.AdminRoleVO;
import com.hiv.common.response.RolePermissionVO;
import com.hiv.common.utils.AssertUtil;
import com.hiv.mapper.AdminMapper;
import com.hiv.mapper.AdminRoleMapper;
import com.hiv.mapper.HospitalMapper;
import com.hiv.mapper.PermissionMapper;
import com.hiv.mapper.RoleMapper;
import com.hiv.mapper.RolePermissionMapper;
import com.hiv.mapper.domain.Admin;
import com.hiv.mapper.domain.AdminRole;
import com.hiv.mapper.domain.Hospital;
import com.hiv.mapper.domain.Permission;
import com.hiv.mapper.domain.Role;
import com.hiv.mapper.domain.RolePermission;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 管理员
 */
@Slf4j
@Service
public class AdminAccountService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private HospitalMapper hospitalMapper;

    /**
     * 查询管理员
     *
     * @param account  账号
     * @param password 密码
     * @return
     */
    public Admin findAdmin(String account, String password) {
        Admin byAccount = adminMapper.findByAccount(account);
        AssertUtil.assertNotNull(byAccount, "账号不存在");
        password = Base64.decodeStr(password);
        Admin admin = adminMapper.findByCondition(account, password);
        AssertUtil.assertNotNull(admin, ErrorCode.USER_OR_PWD_INVALID);
        AssertUtil.assertTrue(admin.getStatus() == 1, "账号已被禁用，请联系管理员");
        Role role = roleMapper.findByAdminId(admin.getId());
        AssertUtil.assertTrue(!(role.getId() == 4 || role.getId() == 5), "账号无权限");
        AssertUtil.assertNotNull(role, "非法的用户,角色不存在,联系管理员");
        admin.setRoleId(role.getId());

        /** 获取权限 */
        Set<Permission> permissionSet = new HashSet<>();
        List<Role> roles = adminRoleMapper.findByAdminId(admin.getId());
        for (Role item : CollectionUtils.emptyIfNull(roles)) {
            List<Permission> permissions = rolePermissionMapper.findByRoleId(item.getId());
            for (Permission permission : CollectionUtils.emptyIfNull(permissions)) {
                if (permission.getParentId() != 0) {
                    //兼容处理多层级前端半选的情况
                    Permission parent = permissionMapper.findById(permission.getParentId());
                    permissionSet.add(parent);
                }
                permissionSet.add(permission);
            }
        }
        List<String> permissionCodes = permissionSet.stream().sorted(Comparator.comparing(Permission::getId)).map(Permission::getCode).collect(Collectors.toList());
        admin.setPermissionCodes(permissionCodes);
        return admin;
    }

    /**
     * 根据id查询admin
     */
    public Admin queryById(long adminId) {
        return adminMapper.findById(adminId);
    }

    /**
     * 新增管理员
     *
     * @param param 管理员信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean addAdmin(AdminAccountAddParam param) {
        // validate
        AssertUtil.assertTrue(param.getPassword().equals(param.getConfirmPwd()), ErrorCode.PARAM_ERROR);
        AssertUtil.assertNotNull(param.getAccount(), ErrorCode.PARAM_ERROR, "登录账号为空");
        AssertUtil.assertNotNull(param.getPassword(), ErrorCode.PARAM_ERROR, "登录密码为空");
        Admin admin = new Admin();
        admin.setName(StringUtils.isNotBlank(param.getName()) ? param.getName() : param.getAccount());
        admin.setAccount(param.getAccount());
        admin.setPassword(param.getPassword());
        admin.setType(param.getType());
        admin.setHospitalPid(param.getHospitalPid());
        admin.setHospitalId(param.getHospitalId());
        admin.setSignImage(param.getSignImage());
        admin.setStatus(param.getStatus());
        Admin isExist = adminMapper.findByAccount(admin.getAccount());
        AssertUtil.assertNull(isExist, ErrorCode.ADMIN_IS_EXIST);
        try {
            adminMapper.insert(admin);
        } catch (DuplicateKeyException ex) {
            AssertUtil.assertTrue(false, ErrorCode.PARAM_ERROR, "该账号已存在");
        } catch (Exception ex) {
            AssertUtil.assertTrue(false, ErrorCode.PARAM_ERROR, "创建管理员失败");
        }
        if (CollectionUtils.isNotEmpty(param.getRoleIds())) {
            List<AdminRole> adminRoles = new ArrayList<>();
            for (Long roleId : param.getRoleIds()) {
                AdminRole adminRole = new AdminRole();
                adminRole.setAdminId(admin.getId());
                adminRole.setRoleId(roleId);
                adminRole.setOperator(param.getOperator());

                Long count = adminRoleMapper.findByAdminIdAndRoleId(admin.getId(), roleId);
                if (count == 0) {
                    adminRoles.add(adminRole);
                }
            }
            adminRoleMapper.batchInsert(adminRoles);
        }
        return true;
    }

    /**
     * 更新管理员
     *
     * @param param 管理员信息
     * @return
     */
    public boolean updateAdmin(AdminAccountEditParam param) {
        AssertUtil.assertNotNull(param.getAccount(), ErrorCode.PARAM_ERROR, "登录账号为空");
        AssertUtil.assertNotNull(param.getPassword(), ErrorCode.PARAM_ERROR, "登录密码为空");
        Admin isExist = adminMapper.findByAccount(param.getAccount());
        if (isExist != null) {
            AssertUtil.assertTrue(isExist.getId().equals(param.getId()), ErrorCode.ADMIN_IS_EXIST);
        }

        Admin admin = new Admin();
        admin.setId(param.getId());
        admin.setName(StringUtils.isNotBlank(param.getName()) ? param.getName() : param.getAccount());
        //admin.setAccount(param.getAccount());
        admin.setPassword(param.getPassword());
        //admin.setHospitalPid(param.getHospitalPid());
        //admin.setHospitalId(param.getHospitalId());
        admin.setStatus(param.getStatus());
        admin.setSignImage(param.getSignImage());

        adminMapper.update(admin);
        if (CollectionUtils.isNotEmpty(param.getRoleIds())) {
            List<AdminRole> adminRoles = new ArrayList<>();
            for (Long roleId : param.getRoleIds()) {
                AdminRole adminRole = new AdminRole();
                adminRole.setAdminId(admin.getId());
                adminRole.setRoleId(roleId);
                adminRole.setOperator(param.getOperator());
                adminRoles.add(adminRole);
            }
            adminRoleMapper.deleteByAdminId(admin.getId());
            adminRoleMapper.batchInsert(adminRoles);
        }
        return true;
    }

    /**
     * 更新管理员状态
     *
     * @param param 管理员信息
     * @return
     */
    public boolean updateAdminStatus(Admin param) {
        adminMapper.update(param);
        return true;
    }

    /**
     * 删除管理员
     *
     * @param adminId id
     * @return
     */
    @Transactional
    public boolean removeAdmin(long adminId) {
        adminMapper.delete(adminId);
        adminRoleMapper.deleteByAdminId(adminId);
        return true;
    }

    /**
     * 分页查询管理员
     *
     * @param param 查询参数
     * @return
     */
    public PageInfo<AdminRoleVO> superPageQueryAdmin(Admin admin, PageQueryAdminParam param) {
        List<AdminRoleVO> adminRoleVOS = new ArrayList<>();
        param.setAdminId(admin.getId());
        long cnt = adminMapper.superPageCount(param);
        List<Admin> admins = adminMapper.superPageQuery(param, param.getPageSize(), param.fetchOffSet());
        for (Admin item : admins) {
            List<Role> roles = adminRoleMapper.findByAdminId(item.getId());
            AdminRoleVO rolePermissionVO = new AdminRoleVO(item, roles);
            adminRoleVOS.add(rolePermissionVO);

            if (item.getHospitalId() != null) {
                Hospital hospital = hospitalMapper.selectById(item.getHospitalId());
                if (hospital != null) {
                    List<Long> hospitalLevel = Lists.newArrayList();
                    StringBuilder builder = new StringBuilder();
                    if (hospital.getParentId() != 0) {
                        hospitalLevel.add(hospital.getParentId());
                        Hospital jiGouHospital = hospitalMapper.selectById(hospital.getParentId());
                        if (jiGouHospital != null) {
                            builder.append(jiGouHospital.getName()).append("/");
                        }
                    }
                    hospitalLevel.add(hospital.getId());
                    item.setHospitalLevels(hospitalLevel);

                    builder.append(hospital.getName());
                    item.setHospitalName(builder.toString());
                }
            }
        }
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), adminRoleVOS, cnt);
    }



    /**
     * 分页查询管理员
     *
     * @param param 查询参数
     * @return
     */
    public PageInfo<AdminRoleVO> subPageQueryAdmin(Admin admin, PageQueryAdminParam param) {
        List<AdminRoleVO> adminRoleVOS = new ArrayList<>();
        param.setAdminId(admin.getId());
        long cnt = adminMapper.subPageCount(param);
        List<Admin> admins = adminMapper.subPageQuery(param, param.getPageSize(), param.fetchOffSet());
        for (Admin item : admins) {
            List<Role> roles = adminRoleMapper.findByAdminId(item.getId());
            AdminRoleVO rolePermissionVO = new AdminRoleVO(item, roles);
            adminRoleVOS.add(rolePermissionVO);

            if (item.getHospitalId() != null) {
                Hospital hospital = hospitalMapper.selectById(item.getHospitalId());
                if (hospital != null) {
                    List<Long> hospitalLevel = Lists.newArrayList();
                    StringBuilder builder = new StringBuilder();
                    if (hospital.getParentId() != 0) {
                        hospitalLevel.add(hospital.getParentId());
                        Hospital jiGouHospital = hospitalMapper.selectById(hospital.getParentId());
                        if (jiGouHospital != null) {
                            builder.append(jiGouHospital.getName()).append("/");
                        }
                    }
                    hospitalLevel.add(hospital.getId());
                    item.setHospitalLevels(hospitalLevel);

                    builder.append(hospital.getName());
                    item.setHospitalName(builder.toString());
                }
            }
        }
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), adminRoleVOS, cnt);
    }

    /**
     * 新增角色
     *
     * @param roleAddParam 角色信息
     * @return
     */
    @Transactional
    public boolean addRole(Admin admin, RoleAddParam roleAddParam) {
        Role role = new Role();
        role.setName(roleAddParam.getName());
        role.setDesc(roleAddParam.getDesc());
        role.setPlatform(roleAddParam.getPlatform());
        role.setWechatRoleType(roleAddParam.getWechatRoleType());
        role.setSuperAdminId(roleAddParam.getSuperAdminId());
        role.setHospitalId(roleAddParam.getHospitalId());
        role.setOperator(roleAddParam.getOperator());
        Role isExist = roleMapper.findByNameAndHospital(role.getName(), admin.getHospitalId());
        AssertUtil.assertNull(isExist, ErrorCode.PARAM_ERROR, "角色名称已存在");
        roleMapper.insert(role);
        if (role.getPlatform() == 1) {
            log.info("小程序端角色");
            return true;
        }
        List<RolePermission> rolePermissions = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(roleAddParam.getPermissionIds())) {
            for (Long item : roleAddParam.getPermissionIds()) {
                RolePermission rolePermission = new RolePermission();
                rolePermission.setRoleId(role.getId());
                rolePermission.setPermissionId(item);
                rolePermission.setOperator(roleAddParam.getOperator());
                rolePermissions.add(rolePermission);
            }

            rolePermissions = rolePermissions.stream().filter(distinctByKey(RolePermission::getPermissionId)).collect(Collectors.toList());
            rolePermissionMapper.batchInsert(rolePermissions);
        }
        return true;
    }

    /**
     * 根据指定属性进行去重
     * @param keyExtractor
     * @param <T>
     * @return
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    /**
     * 更新角色
     *
     * @param roleUpdateParam 角色信息
     * @return
     */
    public boolean updateRole(RoleUpdateParam roleUpdateParam) {
        Role role = new Role();
        role.setId(roleUpdateParam.getId());
        role.setName(roleUpdateParam.getName());
        role.setPlatform(roleUpdateParam.getPlatform());
        role.setWechatRoleType(roleUpdateParam.getWechatRoleType());
        role.setSuperAdminId(roleUpdateParam.getSuperAdminId());
        role.setHospitalId(roleUpdateParam.getHospitalId());
        role.setDesc(roleUpdateParam.getDesc());
        role.setOperator(roleUpdateParam.getOperator());
        Role isExist = roleMapper.findByName(role.getName());
        if (isExist != null && isExist.getId() != roleUpdateParam.getId().intValue()) {
            AssertUtil.assertTrue(isExist.getId() == role.getId(), ErrorCode.ROLE_IS_EXIST);
        }
        roleMapper.update(role);
        if (role.getPlatform() == 1) {
            log.info("小程序端角色");
            return true;
        }
        List<RolePermission> rolePermissions = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(roleUpdateParam.getPermissionIds())) {
            for (Long item : roleUpdateParam.getPermissionIds()) {
                RolePermission rolePermission = new RolePermission();
                rolePermission.setRoleId(role.getId());
                rolePermission.setPermissionId(item);
                rolePermission.setOperator(roleUpdateParam.getOperator());
                rolePermissions.add(rolePermission);
            }
            rolePermissionMapper.deleteByRoleId(role.getId());
            rolePermissions = rolePermissions.stream().filter(distinctByKey(RolePermission::getPermissionId)).collect(Collectors.toList());
            rolePermissionMapper.batchInsert(rolePermissions);
        }
        return true;
    }

    /**
     * 删除角色
     *
     * @param roleId 角色id
     * @return
     */
    @Transactional
    public boolean removeRole(long roleId) {
        long cnt = adminRoleMapper.countByRoleId(roleId);
        AssertUtil.assertTrue(cnt == 0, ErrorCode.EXIST_BIND_USER_ERR);
        roleMapper.delete(roleId);
        rolePermissionMapper.deleteByRoleId(roleId);
        return true;
    }

    /**
     * 查询所有角色
     * @return
     */
    public List<Role> listAllRole(Role param) {
        return roleMapper.listAll(param);
    }

    /**
     * 分页查询角色
     *
     * @param param 查询参数
     * @return
     */
    public PageInfo<RolePermissionVO> pageQueryRole(Admin admin,PageQueryRoleParam param) {
        List<RolePermissionVO> rolePermissionVOS = new ArrayList<>();
        long cnt = roleMapper.pageCount(param);
        List<Role> roles = roleMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        for (Role role : roles) {
            List<Permission> permissions = rolePermissionMapper.findByRoleId(role.getId());
            RolePermissionVO rolePermissionVO = new RolePermissionVO(role, permissions);
            rolePermissionVOS.add(rolePermissionVO);
        }
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), rolePermissionVOS, cnt);
    }

    /**
     * 查询全部权限
     *
     * @return
     */
    public List<Permission> listAllPermission() {
        List<Permission> result = Lists.newArrayList();
        List<Permission> permissions = permissionMapper.findByParentId(0L);
        for (Permission item : CollectionUtils.emptyIfNull(permissions)) {
            if (item.getCode().equals("PERMISSION_PAGE")
                    || Objects.equals(item.getCode(), "HOSPITAL_PAGE")
                    || Objects.equals(item.getCode(), "HOSPITAL_ACCOUNT_PAGE")
                    || Objects.equals(item.getCode(), "BAR_CODE_PAGE")) {
                //将权限管理排除在外
                continue;
            }
            List<Permission> children = permissionMapper.findByParentId(item.getId());
            item.setChildren(children);
            result.add(item);
        }
        return result;
    }

    /**
     * 查询全部权限
     *
     * @return
     */
    public List<Permission> listSubPermission() {
        List<Permission> result = Lists.newArrayList();
        List<Permission> permissions = permissionMapper.findByParentId(0L);
        for (Permission item : CollectionUtils.emptyIfNull(permissions)) {
            if (Objects.equals(item.getCode(), "SYSTEM_PAGE")
                || Objects.equals(item.getCode(), "HOSPITAL_PAGE")
                || Objects.equals(item.getCode(), "BAR_CODE_PAGE")
                || Objects.equals(item.getCode(), "HOSPITAL_ACCOUNT_PAGE")) {
                //将权限管理排除在外
                continue;
            }
            List<Permission> children = permissionMapper.findByParentId(item.getId());
            item.setChildren(children);
            result.add(item);
        }
        return result;
    }

    /**
     * 获取采样员名称
     * @param samplerId
     * @return
     */
    public String getUserName(Long samplerId) {
        if (samplerId == null) {
            return null;
        }

        Admin admin = adminMapper.selectById(samplerId);
        return Optional.ofNullable(admin).map(Admin::getName).orElse(null);
    }

    /**
     * 获取名称
     * @param userId
     * @return
     */
    public String getUserSign(Long userId) {
        if (userId == null) {
            return null;
        }

        Admin admin = adminMapper.selectById(userId);
        return Optional.ofNullable(admin).map(Admin::getSignImage).orElse(null);
    }
}
